#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <functional>
#include <unordered_map>

const static std::string base_sep = "\r\n";      // 基本分隔符
const static std::string line_sep = ": ";        // 行分隔符
const static std::string prefixpath = "wwwroot"; // web根目录
const static std::string homepage = "index.html";
const static std::string httpversion = "HTTP/1.0";
const static std::string spacesep = " ";
const static std::string suffixsep = ".";
const static std::string html_404 = "404.html";
const static std::string arg_sep = "?";

class HttpRequest
{
private:
    // \r\n
    // \r\ndata
    // 获取一行信息
    std::string GetLine(std::string &reqstr)
    {
        auto pos = reqstr.find(base_sep);
        if (pos == std::string::npos) // 没找到分隔符返回空
            return std::string();
        std::string line = reqstr.substr(0, pos);       // 截取一行有效信息
        reqstr.erase(0, line.size() + base_sep.size()); // 删除有效信息和分隔符
        return line.empty() ? base_sep : line;          // 有效信息为空则返回分隔符，不为空返回有效信息
    }
    // 解析请求行
    void ParseReqLine()
    {
        std::stringstream ss(_req_line); // 以空格为分隔符 cin >>
        // /a/b/c.html or /login?user=xxx&passwd=1234 /register
        ss >> _method >> _url >> _version; // 以空格为分隔符依次将请求行的内容赋值给成员变量

        // 以GET方式请求资源，则将参数内容存放到正文
        if (strcasecmp(_method.c_str(), "GET") == 0)
        {
            auto pos = _url.find(arg_sep);
            if (pos != std::string::npos)
            {
                _body_text = _url.substr(pos + arg_sep.size());
                _url.resize(pos); // url 只取参数前的内容
            }
        }

        _path += _url;
        // 只有web根目录返回index.html
        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }

        // wwwroot/index.html
        // wwwroot/image/1.png
        auto pos = _path.rfind(suffixsep);
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }
    // 解析请求报头，以冒号加空格分隔
    void ParseReqHeader()
    {
        for (auto &header : _req_headers)
        {
            auto pos = header.find(line_sep);
            if (pos == std::string::npos)
                continue;
            std::string k = header.substr(0, pos);                // 截取key值
            std::string v = header.substr(pos + line_sep.size()); // 截取value值
            if (k.empty() || v.empty())
                continue;
            _headers_kv.insert(std::make_pair(k, v)); // 将对应的kv值插入到哈希表中
        }
    }

public:
    HttpRequest() : _blank_line(base_sep), _path(prefixpath)
    {
    }
    // 反序列化
    void Deserialize(std::string &reqstr)
    {
        // 基本的反序列化
        _req_line = GetLine(reqstr); // 读取一行，请求行
        // 请求报头
        std::string header;
        do
        {
            header = GetLine(reqstr);
            if (header.empty())
                break;
            else if (header == base_sep)
                break;
            _req_headers.push_back(header);
        } while (true);

        // 正文
        if (!reqstr.empty())
        {
            _body_text = reqstr;
        }

        // 再进一步反序列化
        ParseReqLine();   // 解析请求行
        ParseReqHeader(); // 解析请求报头
    }
    std::string Url()
    {
        LOG(DEBUG, "Client Want url %s\n", _url.c_str());
        return _url;
    }
    std::string Path()
    {
        LOG(DEBUG, "Client Want path %s\n", _path.c_str());
        return _path;
    }
    std::string Suffix()
    {
        return _suffix;
    }
    std::string Method()
    {
        LOG(DEBUG, "Client request method is %s\n", _method.c_str());
        return _method;
    }
    std::string GetRequestBody()
    {
        LOG(DEBUG, "Client request method is %s, args: %s, request path: %s\n",
            _method.c_str(), _body_text.c_str(), _path.c_str());

        return _body_text;
    }
    // 打印请求信息
    void Print()
    {
        std::cout << "---------------------------" << std::endl;
        std::cout << "###" << _req_line << std::endl;
        for (auto &header : _req_headers)
        {
            std::cout << "@@@" << header << std::endl;
        }
        std::cout << "***" << _blank_line;
        std::cout << ">>>" << _body_text << std::endl;

        std::cout << "Method: " << _method << std::endl;
        std::cout << "Url: " << _url << std::endl;
        std::cout << "Version: " << _version << std::endl;

        for (auto head_kv : _headers_kv)
        {
            std::cout << ")))" << head_kv.first << "->"
                      << head_kv.second << std::endl;
        }
    }

    ~HttpRequest()
    {
    }

private:
    // 基本的httprequest的格式
    std::string _req_line;                 // 请求行
    std::vector<std::string> _req_headers; // 请求报头
    std::string _blank_line;               // 空行
    std::string _body_text;                // 正文

    // 更具体的属性字段，需要进一步反序列化
    std::string _method;                                      // 请求方法
    std::string _url;                                         // 统一资源定位符
    std::string _path;                                        // 资源路径
    std::string _suffix;                                      // 资源后缀
    std::string _version;                                     // 版本
    std::unordered_map<std::string, std::string> _headers_kv; // 存储每行报文的哈希表
};

class HttpResponse
{
public:
    HttpResponse() : _version(httpversion), _blank_line(base_sep)
    {
    }
    // 添加状态码
    // void AddCode(int code)
    // {
    //     _status_code = code;
    //     _desc = "OK";
    // }

    void AddCode(int code, const std::string &desc)
    {
        _status_code = code;
        _desc = desc;
    }
    void AddHeader(const std::string &k, const std::string &v)
    {
        _headers_kv[k] = v;
    }
    void AddBodyText(const std::string &body_text)
    {
        _resp_body_text = body_text;
    }
    std::string Serialize()
    {
        // 1.构建状态行
        _status_line = _version + spacesep + std::to_string(_status_code) + spacesep + _desc + base_sep;
        // 2.构建报头
        for (auto &header : _headers_kv)
        {
            std::string header_line = header.first + line_sep + header.second + base_sep;
            _resp_headers.push_back(header_line);
        }
        // 3.空行和正文

        // 4.正式序列化
        std::string responsestr = _status_line;
        for (auto &line : _resp_headers)
        {
            responsestr += line;
        }
        responsestr += _blank_line;
        responsestr += _resp_body_text;

        return responsestr;
    }
    ~HttpResponse()
    {
    }

private:
    // httpresponse base 属性
    std::string _version; // 版本
    int _status_code;     // 状态码
    std::string _desc;    // 状态码描述
    std::unordered_map<std::string, std::string> _headers_kv;

    // 基本的httpresponse的格式
    std::string _status_line;               // 状态行
    std::vector<std::string> _resp_headers; // 应答报头
    std::string _blank_line;                // 空行
    std::string _resp_body_text;            // 响应正文
};

// 回调函数声明
using func_t = std::function<HttpResponse(HttpRequest&)>;

class HttpServer
{
private:
    // 必须以二进制读取文件
    std::string GetFileContent(const std::string path)
    {
        std::ifstream in(path, std::ios::binary); // 以二进制方式打开文件
        if (!in.is_open())
            return std::string();
        in.seekg(0, in.end);       // 将文件读取指针（也称为“get”指针）移动到文件的末尾
        int filesize = in.tellg(); // 获取当前文件读取指针的位置，即文件的总大小，单位字节
        in.seekg(0, in.beg);       // 将文件读取指针重新定位到文件的开始位置

        std::string content;
        content.resize(filesize);                   // 调整 content 的大小为filesize
        in.read((char *)content.c_str(), filesize); // 读取filesize字节的文件内容到 content 中
        in.close();

        return content;
    }

public:
    HttpServer()
    {
        _mine_type.insert(std::make_pair(".html", "text/html"));
        _mine_type.insert(std::make_pair(".jpg", "image/jpg"));
        _mine_type.insert(std::make_pair(".png", "image/png"));
        _mine_type.insert(std::make_pair(".default", "text/html"));

        _code_to_desc.insert(std::make_pair(100, "Continue"));
        _code_to_desc.insert(std::make_pair(200, "OK"));
        _code_to_desc.insert(std::make_pair(201, "Created"));
        _code_to_desc.insert(std::make_pair(301, "Moved Permanently"));
        _code_to_desc.insert(std::make_pair(302, "Found"));
        _code_to_desc.insert(std::make_pair(404, "Not Found"));
    }
    // #define TEST
    std::string HandlerHttpRequest(std::string &reqstr)
    {
#ifdef TEST
        std::cout << "---------------------------------------------" << std::endl;
        std::cout << reqstr;

        // return std::string();
        std::string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n";
        responsestr += "\r\n";
        responsestr += "<html><h1>hello linux,hello net!<h2></html>";

        return responsestr;
#else
        std::cout << "---------------------------------------------" << std::endl;
        std::cout << reqstr;
        std::cout << "---------------------------------------------" << std::endl;

        HttpRequest req; // 构建请求对象
        HttpResponse resp;
        req.Deserialize(reqstr); // 反序列化字符串
        // req.Method();
        // req.GetRequestBody();

        // req.Print();             // 打印反序列的字符串
        // std::string url = req.Url();
        // std::string path = req.Path();

        if (req.Path() == "wwwroot/redir")
        {
            // 重定向处理
            std::string redir_path = "https://www.qq.com"; // 以什么协议去访问
            resp.AddCode(302, _code_to_desc[302]);
            resp.AddHeader("Location", redir_path);
        }
        // 最后服务新增，有参数需要请求服务
        else if(!req.GetRequestBody().empty())
        {
            if(IsServiceExists(req.Path()))
            {
                resp = _service_list[req.Path()](req);
            }
        }
        else
        {
            // 处理静态资源
            std::string content = GetFileContent(req.Path());
            if (content.empty())
            {
                content = GetFileContent("wwwroot/404.html"); // 在默认错误文件获取内容
                // resp.AddCode(404, "Not Found");
                resp.AddCode(404, _code_to_desc[404]); // 内容为空添加404状态码
                resp.AddHeader("Content-Length", std::to_string(content.size()));
                resp.AddHeader("Content-Type", _mine_type["./html"]); // 类型默认为./html
                resp.AddBodyText(content);
            }
            else
            {
                // resp.AddCode(200, "OK");
                resp.AddCode(200, _code_to_desc[200]);
                resp.AddHeader("Content-Length", std::to_string(content.size()));
                resp.AddHeader("Content-Type", _mine_type[req.Suffix()]);
                resp.AddHeader("Set-Cookie", "username=zhangsan");
                resp.AddBodyText(content);
            }
        }

        // 最基础的上层处理
        // HttpResponse resp;
        // std::string content = GetFileContent(req.Path());

        // if (content.empty())
        //     return std::string(); // TODO
        // resp.AddCode(200);
        // resp.AddHeader("Content-Length", std::to_string(content.size()));
        // resp.AddHeader("Content-Type", _mine_type[req.Suffix()]);
        // resp.AddBodyText(content);

        // if (content.empty())
        // {
        //     content = GetFileContent("wwwroot/404.html"); // 在默认错误文件获取内容
        //     // resp.AddCode(404, "Not Found");
        //     resp.AddCode(404, _code_to_desc[404]); // 内容为空添加404状态码
        //     resp.AddHeader("Content-Length", std::to_string(content.size()));
        //     resp.AddHeader("Content-Type", _mine_type["./html"]); // 类型默认为./html
        //     resp.AddBodyText(content);
        // }
        // else
        // {
        //     // resp.AddCode(200, "OK");
        //     resp.AddCode(200, _code_to_desc[200]);
        //     resp.AddHeader("Content-Length", std::to_string(content.size()));
        //     resp.AddHeader("Content-Type", _mine_type[req.Suffix()]);
        //     resp.AddBodyText(content);
        // }
        return resp.Serialize();

        // return std::string();    // 保证编译通过
#endif
    }
    void InsertService(const std::string &servicename, func_t f)
    {
        std::string s = prefixpath + servicename;
        _service_list[s] = f;
    }
    bool IsServiceExists(const std::string servicename)
    {
        auto iter = _service_list.find(servicename);
        if(iter == _service_list.end()) return false;
        else return true;
    }
    ~HttpServer()
    {
    }

private:
    std::unordered_map<std::string, std::string> _mine_type; // 类型对应表
    std::unordered_map<int, std::string> _code_to_desc;      // 状态转描述表
    std::unordered_map<std::string, func_t> _service_list;   // 服务列表
};